package com.zhuang.intelnet.qqserver.qqserver;

import com.zhuang.intelnet.qqserver.qqcommon.Message;
import com.zhuang.intelnet.qqserver.qqcommon.MessageType;
import com.zhuang.intelnet.qqserver.qqcommon.User;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ConcurrentHashMap;

public class QQServer {
	private ServerSocket ss = null;
	// 创建一个集合，存放多个用户，如果是这些用户登录，就认为是合法
	// 这里我们也可以使用 ConcurrentHashMap, 可以处理并发的集合，没有线程安全
	// HashMap 没有处理线程安全，因此在多线程情况下是不安全
	// ConcurrentHashMap 处理的线程安全,即线程同步处理, 在多线程情况下是安全
	private static ConcurrentHashMap<String, User> validUsers = new ConcurrentHashMap<>();
	// private static ConcurrentHashMap<String, ArrayList<Message>> offLineDb = new
	// ConcurrentHashMap<>();

	static { // 在静态代码块，初始化 validUsers

		validUsers.put("100", new User("100", "123456"));
		validUsers.put("200", new User("200", "123456"));
		validUsers.put("300", new User("300", "123456"));
		validUsers.put("400", new User("400", "123456"));
		validUsers.put("500", new User("500", "123456"));
		validUsers.put("600", new User("600", "123456"));

	}

	// 验证用户是否有效的方法
	private boolean checkUser(String userId, String passwd) {

		User user = validUsers.get(userId);
		// 过关的验证方式
		// 说明userId没有存在validUsers 的key中
		if (user == null) {
			return false;
		}
		// userId正确，但是密码错误
		if (!user.getPasswd().equals(passwd)) {
			return false;
		}
		return true;
	}

	public QQServer() {
		// 注意：端口可以写在配置文件.
		try {
			System.out.println("服务端在9999端口监听...");
			// 启动推送新闻的线程
			new Thread(new SendNewsToAllService()).start();
			ss = new ServerSocket(9999);
			// 当和某个客户端连接后，会继续监听, 因此while
			while (true) {
				// 如果没有客户端连接，就会阻塞在这里
				Socket socket = ss.accept();
				// 得到socket关联的对象输入流
				ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());

				// 得到socket关联的对象输出流
				ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());

				// 读取客户端发送的User对象
				User u = (User) ois.readObject();
				// 创建一个Message对象，准备回复客户端
				Message message = new Message();
				// 验证用户 方法
				// 登录通过
				if (checkUser(u.getUserId(), u.getPasswd())) {
					message.setMesType(MessageType.MESSAGE_LOGIN_SUCCEED);
					// 将message对象回复客户端
					oos.writeObject(message);
					// 创建一个线程，和客户端保持通信, 该线程需要持有socket对象
					ServerConnectClientThread serverConnectClientThread = new ServerConnectClientThread(socket,
							u.getUserId());
					// 启动该线程
					serverConnectClientThread.start();
					// 把该线程对象，放入到一个集合中，进行管理.
					ManageClientThreads.addClientThread(u.getUserId(), serverConnectClientThread);

				} else { // 登录失败
					System.out.println("用户 id=" + u.getUserId() + " pwd=" + u.getPasswd() + " 验证失败");
					message.setMesType(MessageType.MESSAGE_LOGIN_FAIL);
					oos.writeObject(message);
					// 关闭socket
					socket.close();
				}
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 如果服务器退出了while，说明服务器端不在监听，因此关闭ServerSocket
			try {
				assert ss != null;
				ss.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

}
